package com.mf.exceptions;

import com.mf.result.Result;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * ClassName: GraceExceptionHandler
 * Package: com.mf.exceptions
 * Description:统一异常拦截处理 可以针对异常的类型进行捕获，然后返回json信息到前端
 *
 * @Author: lmf
 * @Create: 2024/5/27 15:57
 * @Version: 1.0
 */


@ControllerAdvice
public class GraceExceptionHandler {

    /**
     * 处理自定义异常的异常处理器。
     * 当发生{@link MyCustomException}时，将异常信息封装为失败的结果返回。
     *
     * @param e 自定义异常对象，包含错误信息。
     * @return 返回一个表示操作失败的结果对象，其中包含异常的错误信息。
     */
    @ExceptionHandler(MyCustomException.class)
    @ResponseBody
    public Result<String> returnMyException(MyCustomException e) {
        return Result.fail(e.getMessage());
    }

    /**
     * 处理自定义异常的异常处理器。
     * 当发生 {@link MyCustomMsgException} 异常时，将错误信息封装成 {@link Result} 对象返回。
     */
    @ExceptionHandler(MyCustomMsgException.class)
    @ResponseBody
    public Result<String> returnMyCustomMsgException(MyCustomMsgException e) {
        // 将错误信息转化为失败结果对象返回
        return Result.fail(e.getMessage());
    }

    /**
     * 处理文件上传大小超过限制的异常。
     * 当发生{@link MaxUploadSizeExceededException}时，将异常信息封装为失败的结果返回。
     */
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    @ResponseBody
    public Result<String> returnMaxUploadSize(MaxUploadSizeExceededException e) {
        return Result.fail("文件超出限制");
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseBody
    public Result<String> returnHttpMessageNotReadableException(HttpMessageNotReadableException e) {
        return Result.fail(e.getMessage());
    }
    /**
     * get请求必填参数验证异常
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseBody
    public Result<String> returnMissingServletRequestParameterException(MissingServletRequestParameterException e) {
        return Result.fail(e.getMessage());
    }

    /**
     * 处理方法参数不合法的异常。
     * 当客户端提交的请求参数不满足验证条件时，会抛出此异常。
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public Result<String> returnMethodArgumentNotValid(MethodArgumentNotValidException e) {
        // 获取验证结果
        BindingResult result = e.getBindingResult();
        // 根据验证结果生成错误信息，并返回失败的结果对象
        return Result.fail(getErrors(result));
    }

    /**
     * 处理mysql错误异常
     */
    @ExceptionHandler(SQLException.class)
    @ResponseBody
    public Result<String> returnDataIntegrityViolationException(SQLException e) {
        if(e.getMessage().contains("Duplicate entry")){
            return Result.fail("数据重复: " + e.getMessage());
        }
        return Result.fail(e.getMessage());
    }


    /**
     * 获取数据绑定错误信息。
     * 从{@link BindingResult}中提取字段错误信息，并将其映射为字段名到错误信息的映射表。
     */
    public String getErrors(BindingResult result) {
        StringBuilder  message = new StringBuilder();
        List<FieldError> errorList = result.getFieldErrors();
        for (FieldError ff : errorList) {
            // 将每个字段错误的信息添加到映射表中
            String field = ff.getField();
            String msg = ff.getDefaultMessage();
            message.append(field).append(":").append(msg).append(";");
        }
        return message.toString();
    }

}
